#include <gtest/gtest.h>
#include <dtalk/dtalk_item.h>
using namespace dtalk;
using namespace gdface::log;
using namespace gdface;

TEST(TestOption, TestParsetItem) {
	nlohmann::json j;
	j = "hello,\"world\"";
	std::cout << j.get<std::string>() << std::endl;
	std::cout << j.dump() << std::endl;
	j = 1;
	std::cout << j.dump() << std::endl;
	std::string message = "{\"path\":\"/\",\"catalog\":\"MENU\"}";
	auto item = dtalk::from_json(message);
	std::cout << json_utilits::name_of(item->getCatalog(),dtalk::json()) << std::endl;
}

TEST(TestOption, TestParsetDate) {

	{
		std::tm _tm;
		if (date::parset_datetime("2014-11-12T19:12:14", _tm))
		{
			std::cout << std::to_string(_tm) << std::endl;
		}
	}
	{
		std::time_t _t;
		if (date::parset_datetime("2014-11-12T19:12:14", _t))
		{
			std::cout << std::chrono::to_string(_t) << std::endl;
		}
	}
	std::cout << date::parse_uni_datetime("2014-11-12T19:12:14.505") << std::endl;
	auto mills = date::parse_uni_datetime("2014-11-12T19:12:14.505");
	std::cout << date::format("%FT%T%z", mills ) << std::endl;
	std::cout << date::format("%FT%T%Z", mills ) << std::endl;
	std::cout << date::format_iso8601(mills) << std::endl;
	std::cout << date::parse_uni_datetime("2014-11-12T19:12:14") << std::endl;
	std::cout << date::parse_uni_datetime("2014-11-12") << std::endl;
	std::cout << date::parse_uni_datetime("12:12:14") << std::endl;

	std::cout << date::parse_uni_datetime("2014-11-12T19:12:14.505Z") << std::endl;
	std::cout << date::parse_uni_datetime("2014-11-12T19:12:14.505+0800") << std::endl;
	std::cout << date::parse_uni_datetime("2014-11-12T19:12:14+0800") << std::endl;
	std::cout << date::parse_uni_datetime("2014-11-12T19:12:14+8") << std::endl;
	{
		std::tm _tm;
		if (date::parse_uni_datetime("2014-11-12T19:12:14.505+0800", _tm))
		{
			char buffer[80];
			std::strftime(buffer, sizeof(buffer), "%F %T", &_tm);
			std::cout << buffer << std::endl;
		}
	}
	{
		std::time_t _time;
		if (date::parse_uni_datetime("2014-11-12T19:12:14.505+0800", _time))
		{
			std::tm* _tm =  std::localtime(&_time);
			char buffer[80];
			std::strftime(buffer, sizeof(buffer), "%F %T", _tm);
			std::cout << buffer << std::endl;
			std::cout << date::format_iso8601(_time) << std::endl;
			std::cout << date::format_iso8601(*_tm) << std::endl;
		}
	}
}

TEST(TestOption, TestBase64Option) {
	
	auto opt = make_option_shared<Base64Option>("base64Test","binary option","","just for test",0);
	std::string data = "A legendary rivalry reemerges when Jerry moves into New York City's finest hotel";
	SAMPLE_LOG("data size {}", data.size());
	EXPECT_EQ(opt->contentOfValue().size(), 0);
	opt->setValue<std::string>(data);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("base64 Option {}", jstr);
	SAMPLE_LOG("base64 Option contentOfValue [{}]", opt->contentOfValue());
	auto vptr = opt->getValue<std::string>();
	ASSERT_TRUE(vptr);
	ASSERT_TRUE(*vptr == data);
	//EXPECT_EQ(1, 1);
	{
		auto opt2 = make_item_shared<Base64Option>();
		opt2->from_json(jstr);
		ASSERT_TRUE(opt2);
		dtalk::json j2 = opt2->toJson();
		auto jstr2 = j2.dump();
		SAMPLE_LOG("parsed base64 Option {}", jstr2);
	}
	{
		auto opt2 = dtalk::from_json(jstr);
		ASSERT_TRUE(opt2);
		dtalk::json j2 = opt2->toJson();
		auto jstr2 = j2.dump();
		SAMPLE_LOG("parsed base64 Option {}", jstr2);
	}
}

TEST(TestOption, TestIPv4Option) {
	auto opt = make_option_shared<IPv4Option>("IPv4Test","IPV4 option", "","just for test", 0);
	std::string ip = "192.168.10.140";
	opt->asValue(ip);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("IPV4 Option {}", jstr);
	SAMPLE_LOG("IPV4 Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(ip == opt->contentOfValue());
}

TEST(TestOption, TestMACOption) {
	auto opt = make_option_shared<MACOption>("MACTest", "MAC option", "", "just for test", 0);
	std::string mac = "D0:17:C2:D0:3F:BF";
	opt->asValue(mac);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("MAC Option {}", jstr);
	SAMPLE_LOG("MAC Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(tolower(mac) == opt->contentOfValue());
}

TEST(TestOption, TestFloatOption) {
	auto opt = make_option_shared<FloatOption>("FLOATTest", "FLOAT option", "", "just for test", 0);
	std::string vstr = "136.11426411";
	opt->asValue(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("FLOAT Option {}", jstr);
	SAMPLE_LOG("FLOAT Option contentOfValue [{}]", opt->contentOfValue());
	auto p1 = std::atof(opt->contentOfValue().c_str());
	auto p2 = std::atof(vstr.c_str());
	ASSERT_TRUE(p1 == p2);
}

TEST(TestOption, TestIntOption) {
	auto opt = make_option_shared<IntOption>("INTTest", "INT option", "", "just for test", 0);
	std::string vstr = "3721988";
	opt->asValue(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("INT Option {}", jstr);
	SAMPLE_LOG("INT Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(vstr == opt->contentOfValue());
}

TEST(TestOption, TestBoolOption) {
	auto opt = make_option_shared<BoolOption>("BOOLTest", "BOOL option", "", "just for test", 0);
	{
		std::string vstr = "YES";
		opt->asValue(vstr);
		dtalk::json j = opt->toJson();
		auto jstr = j.dump(4);
		SAMPLE_LOG("BOOL Option {}", jstr);
		SAMPLE_LOG("BOOL Option contentOfValue [{}]", opt->contentOfValue());
		ASSERT_TRUE("true" == opt->contentOfValue());
	}
	{
		std::string vstr = "0";
		opt->asValue(vstr);
		dtalk::json j = opt->toJson();
		auto jstr = j.dump(4);
		SAMPLE_LOG("BOOL Option {}", jstr);
		SAMPLE_LOG("BOOL Option contentOfValue [{}]", opt->contentOfValue());
		ASSERT_TRUE("false" == opt->contentOfValue());
	}
}

TEST(TestOption, TestCheckOption1) {
	auto opt = std::make_shared<CheckOption>("CHECKTest", "CHECK option", "", "just for test", 0);
	opt->addOption(2.0f, "option 2");
	opt->addOption(1.75f, "option 1");
	opt->addOption(2.5f, "option 3");
	opt->addOption(3.5f, "option 4");
	SAMPLE_LOG("CHECK contentOfOptions {}",opt->contentOfOptions());
	{
		std::string vstr = "3,0;3,255";
		opt->asValue(vstr);
		auto sel = opt->getSelected<float>();
		SAMPLE_LOG("CHECK Option Selected {}", to_string(sel));
		dtalk::json j = opt->toJson();
		auto jstr = j.dump(4);
		SAMPLE_LOG("CHECK Option {}", jstr);
		SAMPLE_LOG("CHECK Option contentOfValue [{}]", opt->contentOfValue());	
		ASSERT_TRUE("[0,3]" == opt->contentOfValue());
		opt->setSelected<float>({ 3.5f, 2.5f });
		SAMPLE_LOG("CHECK Option contentOfValue [{}]", opt->contentOfValue());
		ASSERT_TRUE("[2,3]" == opt->contentOfValue());
	}
}

TEST(TestOption, TestSwitchOption1) {
	auto opt = std::make_shared<SwitchOption>("SWITCHTest", "SWITCH option", "", "just for test", 0);
	opt->addOption(2.0f, "option 2");
	opt->addOption(1.75f, "option 1");
	opt->addOption(2.5f, "option 3");
	opt->addOption(3.5f, "option 4");
	SAMPLE_LOG("CHECK contentOfOptions {}", opt->contentOfOptions());
	{
		std::string vstr = "2";
		opt->asValue(vstr);
		auto sel = opt->getSelected<float>();
		SAMPLE_LOG("CHECK Option Selected {}", std::to_string(sel));
		dtalk::json j = opt->toJson();
		auto jstr = j.dump(4);
		SAMPLE_LOG("CHECK Option {}", jstr);
		SAMPLE_LOG("CHECK Option contentOfValue [{}]", opt->contentOfValue());
		ASSERT_TRUE("2" == opt->contentOfValue());
		opt->setSelected<float>(3.5f);
		SAMPLE_LOG("CHECK Option contentOfValue [{}]", opt->contentOfValue());
		ASSERT_TRUE("3" == opt->contentOfValue());
	}
}
TEST(TestOption, TestCheckOption2) {
	auto opt = std::make_shared<CheckOption>("CHECKTest2", "CHECK option 2", "", "just for test", 0);
	opt->addOption<std::string>("tom", "option 1");
	opt->addOption<std::string>("jerry", "option 2");
	opt->addOption<std::string>("kitty", "option 3");
	opt->addOption<std::string>("neon", "option 4");
	SAMPLE_LOG("CHECK contentOfOptions {}", opt->contentOfOptions());
	{
		std::string vstr = "3,0;3,4,255";
		opt->asValue(vstr);
		dtalk::json j = opt->toJson();
		auto jstr = j.dump(4);
		SAMPLE_LOG("CHECK Option {}", jstr);
		SAMPLE_LOG("CHECK Option contentOfValue [{}]", opt->contentOfValue());
		ASSERT_TRUE("[0,3]" == opt->contentOfValue());
	}
}

TEST(TestOption, TestDateOption) {
	auto opt = make_option_shared<DateOption>("DATETest", "DATE test", "", "just for test", 0);
	std::string vstr = "2014-11-12T19:12:14";
	auto _mills = date::parse_uni_datetime(vstr);
	auto constr = std::string("\"") + date::format_iso8601(_mills) + std::string("\"");
	opt->asValue(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("DATE Option {}", jstr);
	SAMPLE_LOG("DATE Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(constr == opt->contentOfValue());
	opt->setValue(_mills);
	SAMPLE_LOG("DATE Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(constr == opt->contentOfValue());
	std::time_t _t = std::chrono::system_clock::to_time_t(_mills);
	opt->setValue(_t);
	SAMPLE_LOG("DATE Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(constr == opt->contentOfValue());
	auto _tm = *std::localtime(&_t);
	opt->setValue(_tm);
	SAMPLE_LOG("DATE Option contentOfValue [{}]", opt->contentOfValue());
	ASSERT_TRUE(constr == opt->contentOfValue());

}

TEST(TestOption, TestPasswordOption) {
	auto opt = make_option_shared<PasswordOption>("PASSWORDTest", "PASSWORD option", "", "just for test", 0);
	std::string vstr = "HELLOWORLD";
	opt->asValue(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("PASSWORD Option {}", jstr);
	SAMPLE_LOG("PASSWORD Option contentOfValue [{}]", opt->contentOfValue());
}
TEST(TestOption, TestEmailOption) {
	auto opt = make_option_shared<EmailOption>("EMAILTest", "EMAIL option", "", "just for test", 0);
	std::string vstr = "10km0811@sohu.com";
	opt->asValue(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("EMAIL Option {}", jstr);
	SAMPLE_LOG("EMAIL Option contentOfValue [{}]", opt->contentOfValue());
}

TEST(TestOption, TestMphoneOption) {
	auto opt = make_option_shared<MphoneOption>("MPHONETest", "MPHONE option", "", "just for test", 0);
	std::string vstr = "13611426411";
	opt->asValue(vstr);
	opt->addAvailable({ "13605195470","13891580717","13611426423" });
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("MPHONE Option {}", jstr);
	SAMPLE_LOG("MPHONE Option contentOfValue [{}]", opt->contentOfValue());
}

TEST(TestOption, TestIdnumOption) {
	auto opt = make_option_shared<IdnumOption>("IDNUMTest", "IDNUM option", "", "just for test", 0);
	opt->addListener<std::string>([](const std::string &v) { SAMPLE_LOG("VALUE CHANGE! ---->{}",v); });
	std::string vstr = "33011320000111483X";
	opt->asValue(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("IDNUM Option {}", jstr);
	SAMPLE_LOG("IDNUM Option contentOfValue [{}]", opt->contentOfValue());

}

TEST(TestOption, TestUrlOption) {
	auto opt = make_option_shared<UrlOption>("URLTest", "URL option", "", "just for test", 0);
	std::string vstr = "https://blog.csdn.net/mayue_web/article/details/88406527";
	opt->asValue(vstr);
	opt->updateFrom(vstr);
	dtalk::json j = opt->toJson();
	auto jstr = j.dump(4);
	SAMPLE_LOG("URL Option {}", jstr);
	SAMPLE_LOG("URL Option contentOfValue [{}]", opt->contentOfValue());
}

TEST(TestOption, TestMenuItem) {
	auto item = make_item_shared<MenuItem>("MENUTest", "MENU option", "", "just for test", 0);
	auto opt1 = make_option_shared<MphoneOption>("MPHONETest", "MPHONE option", "", "just for test", 0, "13611426411");
	auto opt2 = make_option_shared<UrlOption>("URLTest", "URL option", "", "just for test",0, "https://blog.csdn.net/mayue_web/article/details/88406527");
	auto opt3 = make_option_shared<IdnumOption>("IDNUMTest", "IDNUM option", "", "just for test", 0, "33011320000111483X");
	auto opt4 = make_option_shared<DateOption>("DATETest", "DATE option", "", "just for test", 0, "2014-11-12T19:12:14+0800");
	item->addChilds({ opt1,opt2,opt3,opt4 });

	auto item_top = make_item_shared<MenuItem>("MENUTestTop", "MENU option", "", "just for test", 0);
	item_top->addChilds({ item });
	dtalk::json j = item_top->toJson();

	auto jstr = j.dump(4);
	SAMPLE_LOG("MENU Option {}", jstr);
	SAMPLE_LOG("MENU Option item_top.childNames {}", std::to_string(item_top->childNames()));	
	SAMPLE_LOG("MENU Option item.childNames {}", item->childNames().dump(4));
}
